﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Transport.Channels;

namespace AiMei.Redis.Core
{
    public class RedisDecoder : ByteToMessageDecoder
    {
        char [] commandEndChar =new char[] { '\r' ,'\n'};
        protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output)
        {
            int length=input.ReadableBytes;
            if (length <= 0) return;
            input.MarkReaderIndex();
            byte commandStartType = input.ReadByte();
            RedisObject result = null ;
            try
            {
                switch ((RedisMessageType)commandStartType)
                {
                    case RedisMessageType.SimpleString:
                        result=ReadString(input);
                        break;
                    case RedisMessageType.Error:
                        result = ReadString(input);
                        break;
                    case RedisMessageType.Integer:
                        result = ReadInteger(input);
                        break;
                    case RedisMessageType.BulkString:
                        result= ReadMultiLine(input);
                        break;
                    case RedisMessageType.ArrayHeader:
                        result = ReadArray(input);
                        break;
                    default:
                        result = null;
                        break;
                }
            }
            catch (Exception ex)
            {

                input.ResetReaderIndex();
                return;
            }
            if (result != null)
            {
                output.Add(result);
            }
        }

        private SimpleString ReadString(IByteBuffer input)
        {
            List<byte> list = new List<byte>();
            while (true)
            {
                byte byteInfo = input.ReadByte();
                if (byteInfo == commandEndChar[0])
                {
                    byte newByteInfo = input.ReadByte();
                    if (newByteInfo == commandEndChar[1])
                    {
                        break;
                    }
                    else
                    {
                        list.Add(byteInfo);
                        list.Add(newByteInfo);

                    }
                }
                else
                {
                    list.Add(byteInfo);
                }

            }
            var str=System.Text.Encoding.UTF8.GetString(list.ToArray());

            SimpleString simpleString = new SimpleString() { Content = str };
            return simpleString;
        }

        private RedisInterget ReadInteger(IByteBuffer input)
        {
            var str = ReadString(input);
            int result = Convert.ToInt32(str.Content);
            RedisInterget redisInterget = new RedisInterget()
            {
                Interget = result
            };
            return redisInterget;
        }


        private MulitString ReadMultiLine(IByteBuffer input)
        {
            Int32 strLength = ReadInteger(input).Interget;
            Int32 packLength = input.ReaderIndex + strLength + 2;
            ////包的长度，比实际包还要大，跳过他，防止堆积
            //if ( input.WriterIndex> packLength)
            //{
            //    input.SkipBytes(input.ReadableBytes);
            //}
            if (strLength == -1)
            {
                return null;
            }
            //包的长度，比实际包还小 拆包
            if (packLength > input.WriterIndex)
            {
                throw new Exception("");
            }
            string str = input.ReadString(strLength,Encoding.UTF8);
            input.ReadBytes(2);
            return new MulitString() { Content = str };
        }


        private RedisArray ReadArray(IByteBuffer input)
        {
            RedisArray array = new RedisArray();
            int arrayLenght = ReadInteger(input).Interget;
            int i = 1;
            while (i++<=arrayLenght)
            {
                byte commandStartType = input.ReadByte();
                switch ((RedisMessageType)commandStartType)
                {
                    case RedisMessageType.SimpleString:
                        var simpleString = this.ReadString(input);
                        array.Array.Add(simpleString);
                        break;
                    case RedisMessageType.Error:
                        var errString = this.ReadString(input);
                        array.Array.Add(errString);
                        break;
                    case RedisMessageType.Integer:
                        var interger = this.ReadInteger(input);
                        array.Array.Add(interger);
                        break;
                    case RedisMessageType.BulkString:
                        var multi = this.ReadMultiLine(input);
                        array.Array.Add(multi);
                        break;
                    case RedisMessageType.ArrayHeader:
                        var subArray = ReadArray(input);
                        array.Array.Add(subArray);
                        break;
                    default:
                        break;
                }
            }
            return array;
        }



    }
}
